home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / c-client / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-29  |  8.3 KB  |  287 lines

  1. /*
  2.  * Program:    Simple Mail Transfer Protocol (SMTP) routines
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    27 July 1988
  13.  * Last Edited:    8 March 1992
  14.  *
  15.  * Sponsorship:    The original version of this work was developed in the
  16.  *        Symbolic Systems Resources Group of the Knowledge Systems
  17.  *        Laboratory at Stanford University in 1987-88, and was funded
  18.  *        by the Biomedical Research Technology Program of the National
  19.  *        Institutes of Health under grant number RR-00785.
  20.  *
  21.  * Original version Copyright 1988 by The Leland Stanford Junior University.
  22.  * Copyright 1992 by the University of Washington.
  23.  *
  24.  *  Permission to use, copy, modify, and distribute this software and its
  25.  * documentation for any purpose and without fee is hereby granted, provided
  26.  * that the above copyright notices appear in all copies and that both the
  27.  * above copyright notices and this permission notice appear in supporting
  28.  * documentation, and that the name of the University of Washington or The
  29.  * Leland Stanford Junior University not be used in advertising or publicity
  30.  * pertaining to distribution of the software without specific, written prior
  31.  * permission.  This software is made available "as is", and
  32.  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
  33.  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
  34.  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  35.  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
  36.  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
  37.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  38.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  39.  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
  40.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  41.  *
  42.  */
  43.  
  44. #include <ctype.h>
  45. #include <stdio.h>
  46. #if unix
  47. #include <sys/types.h>
  48. #endif
  49. #include "osdep.h"
  50. #include "mail.h"
  51. #include "smtp.h"
  52. #include "rfc822.h"
  53. #include "misc.h"
  54.  
  55. /* Mail Transfer Protocol open connection
  56.  * Accepts: service host list
  57.  *        initial debugging flag
  58.  * Returns: T on success, NIL on failure
  59.  */
  60.  
  61. SMTPSTREAM *smtp_open (hostlist,debug)
  62.     char **hostlist;
  63.     long debug;
  64. {
  65.   SMTPSTREAM *stream = NIL;
  66.   void *tcpstream;
  67.   char tmp[MAILTMPLEN];
  68.   if (!(hostlist && *hostlist)) mm_log ("Missing MTP service host",ERROR);
  69.   else do {            /* try to open connection */
  70.     if (tcpstream = tcp_open (*hostlist,SMTPTCPPORT)) {
  71.       stream = (SMTPSTREAM *) fs_get (sizeof (SMTPSTREAM));
  72.       stream->tcpstream = tcpstream;
  73.       stream->debug = debug;
  74.       stream->reply = NIL;
  75.                 /* get SMTP greeting */
  76.       if (smtp_reply (stream) == SMTPGREET &&
  77.       ((smtp_send (stream,"HELO",tcp_localhost (tcpstream)) == SMTPOK) ||
  78.        ((!strcmp ("localhost",lcase (strcpy (tmp,*hostlist)))) &&
  79.         (smtp_send (stream,"HELO","localhost") == SMTPOK))))
  80.     return stream;        /* success return */
  81.       smtp_close (stream);    /* otherwise punt stream */
  82.     }
  83.   } while (*++hostlist);    /* try next server */
  84.   return NIL;
  85. }
  86.  
  87.  
  88. /* Mail Transfer Protocol close connection
  89.  * Accepts: stream
  90.  */
  91.  
  92. void smtp_close (stream)
  93.     SMTPSTREAM *stream;
  94. {
  95.   if (stream) {            /* send "QUIT" */
  96.     smtp_send (stream,"QUIT",NIL);
  97.                 /* close TCP connection */
  98.     tcp_close (stream->tcpstream);
  99.     if (stream->reply) fs_give ((void **) &stream->reply);
  100.     fs_give ((void **) &stream);/* flush the stream */
  101.   }
  102. }
  103.  
  104. /* Mail Transfer Protocol deliver mail
  105.  * Accepts: stream
  106.  *        delivery option (MAIL, SEND, SAML, SOML)
  107.  *        message envelope
  108.  *        message body
  109.  * Returns: T on success, NIL on failure
  110.  */
  111.  
  112. long smtp_mail (stream,type,env,body)
  113.     SMTPSTREAM *stream;
  114.     char *type;
  115.     ENVELOPE *env;
  116.     BODY *body;
  117. {
  118.   char tmp[8*MAILTMPLEN];
  119.   long error = NIL;
  120.   if (!(env->to || env->cc || env->bcc)) {
  121.                   /* no recipients in request */
  122.     smtp_fake (stream,SMTPHARDERROR,"No recipients specified");
  123.     return NIL;
  124.   }
  125.                   /* make sure stream is in good shape */
  126.   smtp_send (stream,"RSET",NIL);
  127.   strcpy (tmp,"FROM:<");    /* compose "MAIL FROM:<return-path>" */
  128.   rfc822_address (tmp,env->return_path);
  129.   strcat (tmp,">");
  130.                 /* send "MAIL FROM" command */
  131.   if (!(smtp_send (stream,type,tmp) == SMTPOK)) return NIL;
  132.                 /* negotiate the recipients */
  133.   if (env->to) smtp_rcpt (stream,env->to,&error);
  134.   if (env->cc) smtp_rcpt (stream,env->cc,&error);
  135.   if (env->bcc) smtp_rcpt (stream,env->bcc,&error);
  136.   if (error) {            /* any recipients failed? */
  137.                       /* reset the stream */
  138.     smtp_send (stream,"RSET",NIL);
  139.     smtp_fake (stream,SMTPHARDERROR,"One or more recipients failed");
  140.     return NIL;
  141.   }
  142.                 /* negotiate data command */
  143.   if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
  144.                 /* set up error in case failure */
  145.   smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  146.                 /* output data, return success status */
  147.   return rfc822_output (tmp,env,body,smtp_soutr,stream->tcpstream) &&
  148.     (smtp_send (stream,".",NIL) == SMTPOK);
  149. }
  150.  
  151. /* Mail Transfer Protocol turn on debugging telemetry
  152.  * Accepts: stream
  153.  */
  154.  
  155. void smtp_debug (stream)
  156.     SMTPSTREAM *stream;
  157. {
  158.   stream->debug = T;        /* turn on protocol telemetry */
  159. }
  160.  
  161.  
  162. /* Mail Transfer Protocol turn off debugging telemetry
  163.  * Accepts: stream
  164.  */
  165.  
  166. void smtp_nodebug (stream)
  167.     SMTPSTREAM *stream;
  168. {
  169.   stream->debug = NIL;        /* turn off protocol telemetry */
  170. }
  171.  
  172. /* Internal routines */
  173.  
  174.  
  175. /* Simple Mail Transfer Protocol send recipient
  176.  * Accepts: SMTP stream
  177.  *        address list
  178.  *        pointer to error flag
  179.  */
  180.  
  181. void smtp_rcpt (stream,adr,error)
  182.     SMTPSTREAM *stream;
  183.     ADDRESS *adr;
  184.     long *error;
  185. {
  186.   char tmp[MAILTMPLEN];
  187.   while (adr) {
  188.                 /* clear any former error */
  189.     if (adr->error) fs_give ((void **) &adr->error);
  190.     strcpy (tmp,"TO:<");    /* compose "RCPT TO:<return-path>" */
  191.     rfc822_address (tmp,adr);
  192.     strcat (tmp,">");
  193.                 /* send "RCPT TO" command */
  194.     if (!(smtp_send (stream,"RCPT",tmp) == SMTPOK)) {
  195.       *error = T;        /* note that an error occurred */
  196.       adr->error = cpystr (stream->reply);
  197.     }
  198.     adr = adr->next;        /* do any subsequent recipients */
  199.   }
  200. }
  201.  
  202.  
  203. /* Simple Mail Transfer Protocol send command
  204.  * Accepts: SMTP stream
  205.  *        text
  206.  * Returns: reply code
  207.  */
  208.  
  209. long smtp_send (stream,command,args)
  210.     SMTPSTREAM *stream;
  211.     char *command;
  212.     char *args;
  213. {
  214.   char tmp[MAILTMPLEN];
  215.                 /* build the complete command */
  216.   if (args) sprintf (tmp,"%s %s",command,args);
  217.   else strcpy (tmp,command);
  218.   if (stream->debug) mm_dlog (tmp);
  219.   strcat (tmp,"\015\012");
  220.                 /* send the command */
  221.   return tcp_soutr (stream->tcpstream,tmp) ? smtp_reply (stream) :
  222.     smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  223. }
  224.  
  225. /* Simple Mail Transfer Protocol get reply
  226.  * Accepts: SMTP stream
  227.  * Returns: reply code
  228.  */
  229.  
  230. long smtp_reply (stream)
  231.     SMTPSTREAM *stream;
  232. {
  233.                 /* flush old reply */
  234.   if (stream->reply) fs_give ((void **) &stream->reply);
  235.                   /* get reply */
  236.   if (!(stream->reply = tcp_getline (stream->tcpstream)))
  237.     return smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  238.   if (stream->debug) mm_dlog (stream->reply);
  239.                 /* handle continuation by recursion */
  240.   return (stream->reply[3]=='-') ? smtp_reply (stream) : atoi (stream->reply);
  241. }
  242.  
  243.  
  244. /* Simple Mail Transfer Protocol set fake error
  245.  * Accepts: SMTP stream
  246.  *        SMTP error code
  247.  *        error text
  248.  * Returns: error code
  249.  */
  250.  
  251. long smtp_fake (stream,code,text)
  252.     SMTPSTREAM *stream;
  253.     long code;
  254.     char *text;
  255. {
  256.                 /* flush any old reply */
  257.   if (stream->reply ) fs_give ((void **) &stream->reply);
  258.                   /* set up pseudo-reply string */
  259.   stream->reply = (char *) fs_get (20+strlen (text));
  260.   sprintf (stream->reply,"%ld %s",code,text);
  261.   return code;            /* return error code */
  262. }
  263.  
  264. /* Simple Mail Transfer Protocol filter mail
  265.  * Accepts: stream
  266.  *        string
  267.  * Returns: T on success, NIL on failure
  268.  */
  269.  
  270. long smtp_soutr (stream,s)
  271.     void *stream;
  272.     char *s;
  273. {
  274.   char c,*t;
  275.                 /* find lines beginning with a "." */
  276.   while (t = strstr (s,"\015\012.")) {
  277.     c = *(t += 3);        /* remember next character after "." */
  278.     *t = '\0';            /* tie off string */
  279.                 /* output prefix */
  280.     if (!tcp_soutr (stream,s)) return NIL;
  281.     *t = c;            /* restore delimiter */
  282.     s = t - 1;            /* push pointer up to the "." */
  283.   }
  284.                 /* output remainder of text */
  285.   return *s ? tcp_soutr (stream,s) : T;
  286. }
  287.